﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Mail;
using System.Data;

namespace DomainModel
{
    public class Patient
    {
        private List<string> _errors;

        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual int MedicalRecordNumber { get; set; }
        public virtual DateTime? DateOfBirth { get; set; }
        public virtual GenderType Gender { get; set; }
        public virtual string PhoneNumber { get; set; }
        public virtual string EmailAddress { get; set; }
        public virtual Address HomeAddress { get; set; }

        public List<string> Errors
        {
            get
            {
                _errors = new List<string>();
                Validate();
                return _errors;
            }
        }

        public bool IsValid
        {
            get
            {
                return Errors.Count == 0;
            }
        }

        public Patient()
        {
            _errors = new List<string>();
            Gender = GenderType.Unknown;
            HomeAddress = new Address();
        }

        public Patient(IDataReader reader)
            : this()
        {
            Id = (int)reader["Id"];
            Name = (string)reader["Name"];
            MedicalRecordNumber = (int)reader["MedicalRecordNumber"];
            Gender = ((GenderType)Enum.Parse(typeof(GenderType), (string)reader["Gender"]));
            DateOfBirth = reader["DateOfBirth"] is DBNull ? (DateTime?)null : (DateTime?)reader["DateOfBirth"];
            PhoneNumber = reader["PhoneNumber"] is DBNull ? null : (string)reader["PhoneNumber"];
            EmailAddress = reader["EmailAddress"] is DBNull ? null : (string)reader["EmailAddress"];
            HomeAddress = new Address(reader);
        }

        private void Validate()
        {
            ValidateName();
            ValidatePhoneNumber();
            ValidateEmailAddress();
            ValidateDateOfBirth();
            ValidateHomeAddress();
        }

        private void ValidateName()
        {
            NameCannotBeEmpty();
            NameCannotBeMoreThan50Characters();
        }

        private void NameCannotBeMoreThan50Characters()
        {
            if (!string.IsNullOrWhiteSpace(Name) && Name.Length > 50)
            {
                _errors.Add("Name cannot be more than 50 characters.");
            }
        }

        private void NameCannotBeEmpty()
        {
            if (string.IsNullOrWhiteSpace(Name))
            {
                _errors.Add("Name cannot be empty.");
            }
        }

        private void ValidatePhoneNumber()
        {
            PhoneNumberCannotBeMoreThan30Characters();
        }

        private void PhoneNumberCannotBeMoreThan30Characters()
        {
            if (!string.IsNullOrWhiteSpace(PhoneNumber) && PhoneNumber.Length > 30)
            {
                _errors.Add("Phone number cannot be more than 30 characters.");
            }
        }

        private void ValidateEmailAddress()
        {
            EmailAddressCannotBeMoreThan30Characters();
            EmailAddressShouldBeInCorrectFormat();
        }

        private void EmailAddressCannotBeMoreThan30Characters()
        {
            if (!string.IsNullOrWhiteSpace(EmailAddress) && EmailAddress.Length > 30)
            {
                _errors.Add("Email address cannot be more than 30 characters.");
            }
        }

        private void EmailAddressShouldBeInCorrectFormat() // xx@xx.com
        {
            if (!string.IsNullOrWhiteSpace(EmailAddress))
            {
                try
                {
                    var emailAddress = new MailAddress(EmailAddress);
                }
                catch (FormatException)
                {
                    _errors.Add("Email address is invalid. Please make sure it is in the following format (For e.g. mano@mano.com).");
                }
            }
        }

        private void ValidateDateOfBirth()
        {
            DateOfBirthCannotBeInTheFuture();
            DateOfBirthCannotBeBefore1900();
        }

        private void DateOfBirthCannotBeInTheFuture()
        {
            if (DateOfBirth.HasValue && DateOfBirth.Value.Date > DateTime.Today)
            {
                _errors.Add("Date of birth cannot be in the future.");
            }
        }

        private void DateOfBirthCannotBeBefore1900()
        {
            if (DateOfBirth.HasValue && DateOfBirth.Value.Date < DateTime.Parse("1900-01-01"))
            {
                _errors.Add("Date of birth cannot be before 01-01-1900. He should be really old!");
            }
        }

        private void ValidateHomeAddress()
        {
            HomeAddressCannotBeNull();
            if (HomeAddress != null)
            {
                _errors.AddRange(HomeAddress.Errors);
            }
        }

        private void HomeAddressCannotBeNull()
        {
            if (HomeAddress == null)
            {
                _errors.Add("Home address cannot be null.");
            }
        }
    }
}
